﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Net;

using BeeZ.CommonObjects.Interfaces;
using BeeZ.Client.Hive;
using BeeZ.Client.Bees;

namespace BeeZ.Client
{

    namespace Bears
    {
        // TODO change to asbtractbear
        public abstract class GeneralBear : IBear
        {
            int workerThreads;
            int portThreads;
            ICollection<IPolicy> policies = null;


            virtual public void Eat(IHoney h)
            {
                
                System.Threading.ThreadPool.GetAvailableThreads(out workerThreads, out portThreads);
                Console.WriteLine("A bear just got some honey! availabe threads: {0}", workerThreads);
            }
            private bool Validate(IHoney h)
            {
                if (policies != null)
                {
                    foreach (IPolicy p in policies)
                    {
                        if (!p.Validate(h))
                        {
                            Console.WriteLine("Did not validate"); //TODO
                            return false;
                        }
                    }
                }
                return true;
            }
            public void AddPolicy(IPolicy p)
            {
                if (policies == null)
                {
                    policies = new HashSet<IPolicy>();
                }
                policies.Add(p);
            }
        }

        // A bear which writes a friendly message to the console
        public class ConsoleBear : GeneralBear
        {

            override public void Eat(IHoney h)
            {
                base.Eat(h);
                Console.WriteLine("at {0:s} a {1} said that {2}", h.GetProperty("Time"), h.GetProperty("Type").ToString(), h.GetFriendlyMessage());
            }
        }

        // A bear which pauses all bees while computer is idle, except for IdleBee
        public class IdleBear : GeneralBear
        {
            Boolean idle = false;

            override public void Eat(IHoney h)
            {
                base.Eat(h);
                //IList<IBee> bees = MainHive.GetBees();

                if (idle == (Boolean)h.GetProperty("Idle"))
                {
                    return;
                }

                if ((Boolean)h.GetProperty("Idle"))
                {
                    idle = true;
                    MainHive.PauseAll(typeof(IIdleSensitive));
                    Console.WriteLine("idlebear just paused all bees");
                }
                else
                {
                    idle = false;
                    MainHive.ResumeAll(typeof(IIdleSensitive));
                    Console.WriteLine("idlebear just resumed all bees");
                }
            }
        }

        public class SendToServerBear : GeneralBear
        {

            override public void Eat(IHoney h)
            {

                base.Eat(h);

                TcpClient client = new TcpClient();
                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.42"), 100);

                client.Connect(serverEndPoint);

                NetworkStream clientStream = client.GetStream();

                // Create a binary formatter.
                byte[] honeyByte = SerializeToByteArray(h);

                // Serialize.
                clientStream.Write(honeyByte, 0, honeyByte.Length);

                clientStream.Flush();

                /*
                IPEndPoint queenBee = new IPEndPoint(System.Net.IPAddress.Parse("192.168.1.42"), 100);
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                socket.Connect(queenBee);

                byte[] honeyByte = SerializeToByteArray(h);

                socket.Send(honeyByte);
                socket.Disconnect(false);
                socket.Close(); */

            }

            private static byte[] SerializeToByteArray(object graph)
            {
                // Create a memory stream, and serialize.
                using (MemoryStream stream = new MemoryStream())
                {
                    // Create a binary formatter.
                    IFormatter formatter = new BinaryFormatter();

                    // Serialize.
                    formatter.Serialize(stream, graph);

                    // Now return the array.
                    return stream.ToArray();
                }
            }
        }

        public class SameAsLastPolicy : IPolicy
        {
            private IHoney lastHoney;

            public bool Validate(IHoney h)
            {
                bool ret = !h.Equals(lastHoney); // TODO time!!!                                            
                lastHoney = h;
                return ret;
            }
        }

        public class WarningHoneyPolicy : MsgStartWithPolicy
        {
            public WarningHoneyPolicy()
                : base("Warning...") {}
        }

        public class ShutdownHoneyPolicy : MsgStartWithPolicy
        {
            public ShutdownHoneyPolicy()
                : base("Shutdown...") { }
        }

        public class MsgStartWithPolicy : IPolicy
        {
            private String starter;

            public MsgStartWithPolicy(String starter) 
            {
                this.starter = starter;
            }

            public bool Validate(IHoney h)
            {
                bool v = h.GetFriendlyMessage().StartsWith(starter);
                if (!v)
                {
                    Console.WriteLine("error msg");
                }
                return v;
            }
        }

    }
}